﻿using NPOI.HSSF.UserModel;
using NPOI.SS.UserModel;
using NPOI.XSSF.UserModel;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;

namespace ConsoleApp1
{

    public class NPOIService
    {
        public void ReadTemp(List<List<MyCell>> cells, string templatePath, string outputDirectoryName = "")
        {
            for (int i = 1; i < cells.Count; i++)
            {
                using (var file = new FileStream(templatePath, FileMode.Open, FileAccess.Read))
                {
                    var doc = new NPOI.XWPF.UserModel.XWPFDocument(file);
                    doc.GetBodyElementsIterator();


                    var body = cells.ToArray()[i];
                    var head = cells.First();

                    foreach (var table in doc.Tables)
                    {
                        foreach (var row in table.Rows)
                        {
                            foreach (var cell in row.GetTableCells())
                            {
                                foreach (var para in cell.Paragraphs)
                                {
                                    ReplaceKeyObjet(para, head, body);
                                }
                            }
                        }
                    }

                    foreach (var para in doc.Paragraphs)
                    {
                        ReplaceKeyObjet(para, head, body);
                    }

                    //var gp = doc.CreateParagraph();
                    //var gr = gp.CreateRun();
                    //gp = doc.CreateParagraph();
                    //gr = gp.CreateRun();
                    //gr.AddChartSpace()



                    var basePath = Path.GetDirectoryName(templatePath);
                    var basePath2 = Path.Combine(basePath, outputDirectoryName);
                    if (!Directory.Exists(basePath2))
                    {
                        Directory.CreateDirectory(basePath2);
                    }
                    //ClearFolder(basePath2);



                    //写文件
                    using (var outFile = new FileStream(Path.Combine(basePath2, i + ".docx"), FileMode.OpenOrCreate))
                    {
                        doc.Write(outFile);
                    }
                }
            }
        }

        public void ClearFolder(string dir, bool delCurrentFolder = false)
        {
            if (Directory.Exists(dir)) //如果存在这个文件夹删除之   
            {
                foreach (string d in Directory.GetFileSystemEntries(dir))
                {
                    if (File.Exists(d))
                        File.Delete(d); //直接删除其中的文件                           
                    else
                        ClearFolder(d, true); //递归删除子文件夹   
                }
                if (delCurrentFolder)
                    Directory.Delete(dir, true); //删除已空文件夹                    
            }
        }

        private static void ReplaceKeyObjet(NPOI.XWPF.UserModel.XWPFParagraph para, List<MyCell> head, List<MyCell> body)
        {
            foreach (var item in head)
            {
                string oldtext = para.ParagraphText;
                if (oldtext == "")
                    continue;
                string temptext = para.ParagraphText;
                if (temptext.Contains("{" + item.v + "}") && item.x < head.Count)
                {
                    temptext = temptext.Replace("{" + item.v + "}", body[item.x]?.v ?? "");
                    para.ReplaceText(oldtext, temptext);
                }
            }
        }

        public DtoResult<List<List<MyCell>>> ReadXLSX(string filePath)//工单明细表(富临)(1)(1)
        {
            var output = DtoResult<List<List<MyCell>>>.CreateResult();
            output.Data = new List<List<MyCell>>();

            using (var file = new FileStream(filePath, FileMode.Open, FileAccess.Read))
            {
                var hssfworkbook = new XSSFWorkbook(file);
                var sheet = hssfworkbook.GetSheetAt(0);

                var rows = sheet.GetRowEnumerator();

                while (rows.MoveNext())
                {
                    var row = (XSSFRow)rows.Current;
                    var bodyRow = new List<MyCell>();
 
                    if (row.PhysicalNumberOfCells != row.LastCellNum)
                    {
                        output.AddError(0,row.Cells.FirstOrDefault()?.RowIndex??0,"数据长度和表头定义长度不一致，请确保数据区域内没有空值单元格");
                        return output;
                    }

                    foreach (var item in row.Cells)
                    {
                        var r = GetData(item, output.Data.FirstOrDefault()?.ToArray());
                        if (r.Success)
                        {
                            bodyRow.Add(r.Data);
                        }
                        else
                        {
                            output.AddError(r.Errors);
                            if (output.Errors.Count > 10)
                                return output;
                        }

                    }
                    output.Data.Add(bodyRow);
                }
                return output;
            }
        }

        public static DtoResult<MyCell> GetData(ICell cell, MyCell[] headerCell = null)
        {
            var output = DtoResult<MyCell>.CreateResult();
            output.Data = new MyCell() { x = cell.ColumnIndex, y = cell.RowIndex };
            if (headerCell != null && headerCell.Length > 0)
            {
                if (cell.ColumnIndex >= headerCell.Length)
                {
                    output.AddError(cell.ColumnIndex, cell.RowIndex, "没有对应表头");
                }
                output.Data.k = headerCell[cell.ColumnIndex]?.v ?? "";
            }


            switch (cell.CellType)
            {
                case CellType.Blank:
                    output.Data.v = "";
                    break;
                case CellType.Boolean:
                    output.Data.v = cell.BooleanCellValue ? "是" : "否";
                    break;
                case CellType.Numeric:
                    if (HSSFDateUtil.IsCellDateFormatted(cell))//日期类型
                    {
                        output.Data.v = cell.DateCellValue.ToString("yyyy-MM-dd");
                    }
                    else//其他数字类型
                    {
                        output.Data.v = cell.ToString();
                    }

                    break;
                case CellType.String:
                    output.Data.v = cell.StringCellValue;
                    break;
                case CellType.Error:
                    output.Data.v = "";
                    output.AddError(cell.ColumnIndex, cell.RowIndex, "Error");
                    break;
                case CellType.Formula:
                    try
                    {
                        output.Data.v = cell.NumericCellValue.ToString();
                    }
                    catch
                    {
                        output.Data.v = cell.StringCellValue;
                    }
                    break;
                default:
                    output.AddError(cell.ColumnIndex, cell.RowIndex, "Unknown");
                    break;
            }
            return output;
        }
    }

    public class MyCell
    {
        public int x { get; set; }
        public int y { get; set; }
        public string k { get; set; }
        public string v { get; set; }
    }

    public class DtoResult<T>
    {
        private List<Error> _error = new List<Error>();

        public static DtoResult<T> CreateResult()
        {
            var result = new DtoResult<T>();
            return result;
        }

        public T Data {
            get; set;
        }

        /// <summary>
        /// 成功
        /// </summary>
        public bool Success {
            get { return _error.Count == 0; }
        }

        /// <summary>
        /// 当请求出现错误时，即Success值为false时，返回引发此错误的描述
        /// </summary>

        public List<Error> Errors { get { return _error.Count == 0 ? null : _error; } }


        public void AddError(int x, int y, string errinfo)
        {
            _error.Add(new Error() { x = x, y = y, ErrorInfo = errinfo });
        }

        public void AddError(Error error)
        {
            _error.Add(error);
        }
        public void AddError(IEnumerable<Error> errors)
        {
            _error.AddRange(errors);
        }
    }

    public class Error
    {
        public int x { get; set; }
        public int y { get; set; }
        /// <summary>
        /// 错误描述信息
        /// </summary>
        public string ErrorInfo { get; set; }

    }
}
